﻿using System;
using System.IO;
using System.Linq;
using System.Threading;
using BigMailer.Client;

namespace BigMailer
{
	public class Uploader : IDisposable
	{
		private bool cancelThread = false;
		private string fileName;
		private FileStream fileStream;
		private string finalUrl;
		private Exception lastError = null;
		private MailerClient proxy = new MailerClient(UiCore.ServiceUsername, UiCore.ServicePassword, UiCore.ServiceUrl);
		private SendStatus status = SendStatus.Active;
		private DateTime uploadStart = DateTime.Now;
		private Thread uploadThread;

		public Uploader(string fileName)
		{
			this.fileName = fileName;
			this.fileStream = new FileStream( fileName, FileMode.Open, FileAccess.Read );

			uploadThread = new Thread( UploadMethod );
			uploadThread.Start();
		}

		public string FileName
		{
			get { return fileName; }
		}

		public long FileSize
		{
			get
			{
				lock ( SyncBlock )
				{
					return fileStream.Length;
				}
			}
		}

		public object SyncBlock
		{
			get { return fileStream; }
		}

		public long Position
		{
			get
			{
				lock ( SyncBlock )
				{
					return fileStream.Position;
				}
			}
		}

		public SendStatus Status
		{
			get { return status; }
		}

		public DateTime StartTime
		{
			get { return uploadStart; }
		}

		public Exception Error
		{
			get { return lastError; }
		}

		public string FinalUrl
		{
			get { return finalUrl; }
		}

		#region IDisposable Members

		public void Dispose()
		{
			if ( status == SendStatus.Active )
			{
				cancelThread = true;
				uploadThread.Join();
			}

			fileStream.Dispose();
		}

		#endregion

		private void UploadMethod()
		{
			try
			{
				proxy.BeginUpload( FileName );
				uploadStart = DateTime.Now;

				byte[] buffer = new byte[131072];//1024*64];
				int readCount = 1;
				while ( !cancelThread && readCount > 0 )
				{
					lock ( SyncBlock )
					{
						readCount = fileStream.Read( buffer, 0, buffer.Length );
					}

					if ( readCount == buffer.Length )
					{
						proxy.AddFilePart( FileName, buffer );
					}
					else if ( readCount > 0 )
					{
						byte[] smallerBuffer = new byte[readCount];
						Array.Copy( buffer, 0, smallerBuffer, 0, readCount );
						proxy.AddFilePart( FileName, smallerBuffer );
					}
				}

				if ( readCount > 0 )
				{
					proxy.AbandonFile( FileName );
					status = SendStatus.Cancelled;
				}
				else
				{
					finalUrl = proxy.CloseFileAndGetUrl( FileName );
				}

				if ( !cancelThread )
				{
					status = SendStatus.Uploaded;
				}
			}
			catch ( Exception x )
			{
				lastError = x;
				status = SendStatus.Errored;
			}
		}

		internal void Cancel()
		{
			cancelThread = true;
			Dispose();
		}
	}
}